﻿using System;
using System.Collections.Generic;
using Gameplay.PVE.Utils;
using Pathfinding;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine;
using UnityEngine.AI;
using Yoozoo.Framework.Core;
using Yoozoo.Gameplay.Liberty;

namespace Gameplay.PVE.Survivor
{
    [CustomEditor(typeof(BattleMonsterData))]
    public class BattlePointDataInspector : UnityEditor.Editor
    {
        private BattleMonsterData _monsterData;
        private int heroId;
        private void OnEnable()
        {
            _monsterData = target as BattleMonsterData;
            OnHeroIdChanged();
        }

        private void OnHeroIdChanged()
        {
            var heroModel = _monsterData.transform.Find("HeroModel");
            if (heroModel != null)
            {
                GameObject.DestroyImmediate(heroModel.gameObject);
            }
            if (BattleConstValue.heroModelNameMap.TryGetValue(_monsterData.heroId, out var modelName))
            {
                var path = "Assets/ResourcesAssets/Pve/Survivor/Prefabs/" + modelName + ".prefab";
                var obj = AssetDatabase.LoadAssetAtPath<GameObject>(path);
                if (obj != null)
                {
                    var go = GameObject.Instantiate(obj);
                    go.transform.SetParent(_monsterData.transform);
                    go.transform.localPosition = Vector3.zero;
                    go.transform.localEulerAngles = Vector3.zero;
                    go.name = "HeroModel";
                    return;
                }
            }
            var defaultGO = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            defaultGO.transform.SetParent(_monsterData.transform);
            defaultGO.transform.localPosition = Vector3.zero;
            defaultGO.transform.localEulerAngles = Vector3.zero;
            defaultGO.name = "HeroModel";
            UnityEngine.Debug.LogError("找不到英雄模型"+_monsterData.heroId);
        }
        
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();
            if (heroId != _monsterData.heroId)
            {
                OnHeroIdChanged();
                heroId = _monsterData.heroId;
            }
        }
    }
    
    [CustomEditor( typeof(BattleMapData))]
    public class BattleMapDataInspector: UnityEditor.Editor
    {
        private BattleMapData mapData;
        private void OnEnable()
        {
            mapData = target as BattleMapData;
        }

        private Dictionary<int,Transform> pointDic = new Dictionary<int, Transform>();
        private Dictionary<int,BattleRegionData> regionDic = new Dictionary<int, BattleRegionData>();
        
        
        public override void OnInspectorGUI()
        {
            if (GUILayout.Button("读取地图"))
            {
                LoadMap();
                LoadPoint();
                LoadRegion();
                LoadMonster();
                //LoadInteractable();
            }
            if (GUILayout.Button("保存地图"))
            {
                SaveAll();
            }

            if (GUILayout.Button("导出Navmesh"))
            {
                var centerPoint = mapData.gameObject.transform.Find("Center");
                if (centerPoint == null)
                {
                    UnityEngine.Debug.LogError("没有找到Center，请在根节点下创建");
                    return;
                }
                
                var helper = centerPoint.gameObject.GetComponent<NavMeshBakeHelper>();
                if (helper == null)
                {
                    helper = centerPoint.gameObject.AddComponent<NavMeshBakeHelper>();
                    helper.x = 200;
                    helper.y = 3;
                    helper.z = 200;
                }
                var mapRoot = mapData.gameObject.transform.Find("MapRoot");
                NavMeshBakeHelper.BakeNavMesh(mapRoot);
                var navMeshData = NavMeshBakeHelper.navMesh;
                var path = "Assets/ResourcesAssets/Pve/Survivor/NavMesh/"+mapData.name+".asset";
                AssetDatabase.DeleteAsset(path);
                AssetDatabase.CreateAsset(navMeshData,path);
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
                mapData.navMeshData = AssetDatabase.LoadAssetAtPath<NavMeshData>(path);
                NavMeshBakeHelper.Clear();
                SaveAll();
            }
            if (GUILayout.Button("读取路点"))
            {
                LoadPath();
            }
            if (GUILayout.Button("重新生成路点"))
            {
                CreatePath();
            }
            if (GUILayout.Button("保存路点"))
            {
                SavePath();
            }
            if (GUILayout.Button("生成出生点"))
            {
                GenerateSpawnPoint();
            }

            if (GUILayout.Button("添加HpState(过渡用)"))
            {
                AddHpState();
            }
            base.OnInspectorGUI();
        }
        
        private void LoadInteractable()
        {
            var root = mapData.gameObject.transform.Find("InteractableRoot");
            /*if (root == null)
            {
                root = new GameObject("InteractableRoot").transform;
                root.SetParent(mapData.gameObject.transform);
                root.transform.localPosition = Vector3.zero;
            }*/
            for (var i = 0; i < mapData.interactables.Count; i++)
            {
                var interactable = mapData.interactables[i];
                var id = interactable.id;
                var go = root.Find(id.ToString());
                if (go != null)
                {
                    var interactableData = go.GetComponent<MapInteractableData>();
                    //interactableData.region = regionDic[interactable.regionId];
                }
            }
        }

        private void LoadMap()
        {
            var root = mapData.gameObject.transform.Find("MapRoot");
            if (root == null)
            {
                root = new GameObject("MapRoot").transform;
                root.SetParent(mapData.gameObject.transform);
                root.transform.localPosition = Vector3.zero;
            }

            var mapName = mapData.scene.mapPrefabName;
            var path = "Assets/ResourcesAssets/Pve/Survivor/Prefabs/"+mapName+".prefab";
            var go = GameObject.Instantiate(AssetDatabase.LoadAssetAtPath<GameObject>(path));
            go.transform.SetParent(root);
            go.transform.localPosition = Vector3.zero;
            go.transform.forward = Vector3.forward;
            var libertySceneManager = go.GetComponentInChildren<LibertySceneManager>();
            if (libertySceneManager)
            {
                var templateRoot = new GameObject("LibertySceneRoot");
                templateRoot.transform.SetParent(go.transform);
                libertySceneManager.ShowAllObjects(templateRoot.transform);
            }
        }

        private void LoadRegion()
        {
            regionDic.Clear();
            var root = mapData.gameObject.transform.Find("RegionRoot");
            if (root == null)
            {
                root = new GameObject("RegionRoot").transform;
                root.SetParent(mapData.gameObject.transform);
                root.transform.localPosition = Vector3.zero;
            }
            foreach (var region in mapData.regions)
            {
                var go = new GameObject();
                go.name = region.id.ToString();
                go.transform.SetParent(root);
                go.transform.position = region.position;
                go.transform.forward = region.forward;
                var regionData = go.AddComponent<BattleRegionData>();
                regionData.shape = (EBattleRegionShapeType)region.shape;
                regionData.shapeParam1 = region.shapeParam1;
                regionData.shapeParam2 = region.shapeParam2;
                regionDic.Add(region.id, regionData);
            }
        }
        
        private void LoadPoint()
        {
            pointDic.Clear();
            var root = mapData.gameObject.transform.Find("PointRoot");
            if (root == null)
            {
                root = new GameObject("PointRoot").transform;
                root.SetParent(mapData.gameObject.transform);
                root.transform.localPosition = Vector3.zero;
            }
            foreach (var point in mapData.points)
            {
                var go = GameObject.CreatePrimitive(PrimitiveType.Cube);
                go.name = point.id.ToString();
                go.transform.SetParent(root);
                go.transform.position = point.position;
                go.transform.forward = point.forward;
                pointDic.Add(point.id, go.transform);
            }
        }
        
        private void LoadMonster()
        {
            var root = mapData.gameObject.transform.Find("MonsterRoot");
            if (root == null)
            {
                root = new GameObject("MonsterRoot").transform;
                root.SetParent(mapData.gameObject.transform);
                root.transform.localPosition = Vector3.zero;
            }
            foreach (var group in mapData.monsterGroup)
            {
                var groupObject = new GameObject(group.id.ToString());
                groupObject.transform.SetParent(root);
                groupObject.transform.localPosition = Vector3.zero;
                groupObject.AddComponent<MonsterGroupData>().fogId = group.fogId;
                //Vector3 averagePosition = Vector3.zero;
                for (int i = 0; i < group.monsters.Count; i++)
                {
                    var point = group.monsters[i];
                    var pointRoot = new GameObject("Point");
                    pointRoot.transform.SetParent(groupObject.transform);
                    pointRoot.transform.localPosition = point.position;
                    pointRoot.transform.forward = point.forward;
                    var pointData = pointRoot.AddComponent<BattleMonsterData>();
                    pointData.heroId = point.heroId;
                    pointData.aiType = point.aiType;
                    pointData.searchRange = point.searchRange;
                    pointData.transmitToGroup = point.transmitToGroup;
                    pointData.unitType = point.unitType;
                    pointData.specialIndex = point.specialIndex;
                    pointData.isPatrol = point.isPatrol;
                    pointData.extraParam1 = point.extraParam1;
                    pointData.extraParam2 = point.extraParam2;
                    pointData.attributeRatio = point.attributeRatio;
                    pointData.team = point.team;
                    if (pointDic.TryGetValue(point.pointId, out var pointTransform))
                    {
                        pointData.point = pointTransform;
                    }
                    var heroId = point.heroId;
                    GameObject go = null;
                    if (BattleConstValue.heroModelNameMap.TryGetValue(heroId, out var name))
                    {
                        var path = "Assets/ResourcesAssets/Pve/Survivor/Prefabs/" + name + ".prefab";
                        var obj = AssetDatabase.LoadAssetAtPath<GameObject>(path);
                        if (obj == null)
                        {
                            go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                        }
                        else
                        {
                            go = GameObject.Instantiate(obj);
                        }
                    }
                    else
                    {
                        go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                    }
                    
                    go.transform.SetParent(pointRoot.transform);
                    go.transform.localPosition = Vector3.zero;
                    go.transform.localEulerAngles = Vector3.zero;
                    go.name = "HeroModel";
                }
            }
        }

        private void SaveAll()
        {
            var newObject = GameObject.Instantiate(this.mapData.gameObject);
            var mapData = newObject.GetComponent<BattleMapData>();
            
            mapData.routes = new List<MapRoute>();
            var truck = mapData.GetComponentInChildren<TruckWheel>();
            var routeRoot = mapData.transform.Find("RouteRoot");
            if (routeRoot != null)
            {
                for (int i = 0; i < routeRoot.childCount; i++)
                {
                    var child = routeRoot.GetChild(i);
                    var route = new MapRoute();
                    route.id = i + 1;
                    route.points = new List<Vector3>();
                    for (int j = 0; j < child.childCount; j++)
                    {
                        var point = child.GetChild(j);
                        route.points.Add(point.position);
                    }
                    mapData.routes.Add(route);
                    /*if (truck != null)
                    {
                        mapData.truckPath.Add(truck.SimulatePath(route,3));
                    }*/
                }
            }
            
            var removeObjectList = new List<Transform>();
            var maxPointId = 0;
            var pointRoot = newObject.transform.Find("PointRoot");
            if (pointRoot != null)
            {
                mapData.points.Clear();
                for (int i = 0; i < pointRoot.childCount; i++)
                {
                    var child = pointRoot.GetChild(i);
                    if (child)
                    {
                        var point = new BattleMapPoint();
                        point.position = child.position;
                        point.position.y = 0;
                        point.forward = child.forward;
                        var name = child.gameObject.name;
                        if (int.TryParse(name, out var id))
                        {
                            point.id = id;
                        }
                        else
                        {
                            point.id = -1;
                        }
                        maxPointId = Mathf.Max(maxPointId, point.id);
                        mapData.points.Add(point);
                        removeObjectList.Add(child);
                    }
                }
            }
            //找到没有分配id的point
            for (int i = 0; i < mapData.points.Count; i++)
            {
                if (mapData.points[i].id == -1)
                {
                    maxPointId++;
                    mapData.points[i].id = maxPointId;
                }
            }
            
            mapData.monsterGroup.Clear();
            var root = newObject.transform.Find("MonsterRoot");
            if (root == null)
            {
                UnityEngine.Debug.LogError("没有找到怪物节点");
                return;
            }
            var maxGroupId = 0;
            for (int i = 0; i < root.childCount; i++)
            {
                var child = root.GetChild(i);
                var groupData = child.GetComponent<MonsterGroupData>();
                //组
                var group = new BattleMapMonsterGroup();
                group.monsters = new List<BattleMapMonster>();
                if (groupData)
                {
                    group.fogId = groupData.fogId;
                }
                for (int j = 0; j < child.childCount; j++)
                {
                    var monster = child.GetChild(j);
                    var point = new BattleMapMonster();
                    point.position = monster.position;
                    point.forward = monster.forward;
                    var pointData = monster.GetComponent<BattleMonsterData>();
                    if (pointData)
                    {
                        point.heroId = pointData.heroId;
                        point.aiType = pointData.aiType;
                        point.searchRange = pointData.searchRange;
                        point.transmitToGroup = pointData.transmitToGroup;
                        point.unitType = pointData.unitType;
                        point.specialIndex = pointData.specialIndex;
                        point.isPatrol = pointData.isPatrol;
                        point.extraParam1 = pointData.extraParam1;
                        point.extraParam2 = pointData.extraParam2;
                        point.attributeRatio = pointData.attributeRatio;
                        point.team = pointData.team;
                        if (pointData.point)
                        {
                            for (int k = 0; k < mapData.points.Count; k++)
                            {
                                if (mapData.points[k].position == pointData.point.position)
                                {
                                    point.pointId = mapData.points[k].id;
                                    break;
                                }
                            }
                        }
                    }
                    group.monsters.Add(point);
                }

                var name = child.gameObject.name;
                if (int.TryParse(name, out var id))
                {
                    group.id = id;
                }
                else
                {
                    group.id = -1;
                }
                mapData.monsterGroup.Add(group);
                removeObjectList.Add(child);
                maxGroupId = Mathf.Max(maxGroupId, group.id);
            }
            //找到没有分配id的group
            for (int i = 0; i < mapData.monsterGroup.Count; i++)
            {
                if (mapData.monsterGroup[i].id == -1)
                {
                    maxGroupId++;
                    mapData.monsterGroup[i].id = maxGroupId;
                }
            }
            
            var mapPrefabRoot = newObject.transform.Find("MapRoot");
            if (mapPrefabRoot != null)
            {
                /*mapData.scene = new BattleMapScene();
                var child = mapPrefabRoot.GetChild(0);
                //去掉括号
                var name = child.name;
                var index = name.IndexOf('(');
                if (index > 0)
                {
                    name = name.Substring(0, index);
                }
                mapData.scene.mapPrefabName = name;*/
                removeObjectList.Add(mapPrefabRoot.GetChild(0));
            }

            var regionId = 0;
            var regionRoot = newObject.transform.Find("RegionRoot");
            var tempList = new List<BattleRegionData>();
            if (regionRoot != null)
            {
                mapData.regions = new List<BattleMapRegion>();
                var battleRegionDataList = regionRoot.GetComponentsInChildren<BattleRegionData>();
                for (int i = 0; i < battleRegionDataList.Length; i++)
                {
                    var regionData = battleRegionDataList[i];
                    var region = new BattleMapRegion();
                    var name = regionData.gameObject.name;
                    if (int.TryParse(name, out var id))
                    {
                        region.id = id;
                    }
                    else
                    {
                        region.id = -1;
                    }
                    tempList.Add(regionData);
                    regionId = Mathf.Max(region.id, regionId);
                    region.position = regionData.transform.position;
                    region.forward = regionData.transform.forward;
                    region.shape = (int)regionData.shape;
                    region.shapeParam1 = regionData.shapeParam1;
                    region.shapeParam2 = regionData.shapeParam2;
                    mapData.regions.Add(region);
                    removeObjectList.Add(regionData.gameObject.transform);
                }
            }
            //找到没有分配id的region
            for (int i = 0; i < mapData.regions.Count; i++)
            {
                if (mapData.regions[i].id == -1)
                {
                    regionId++;
                    mapData.regions[i].id = regionId;
                    tempList[i].gameObject.name = regionId.ToString();
                }
            }

            var interactableId = 0;
            var interactableRoot = newObject.transform.Find("InteractableRoot");
            if (interactableRoot != null)
            {
                var interactableList = interactableRoot.GetComponentsInChildren<MapInteractableData>();
                mapData.interactables = new List<MapInteractableData>();
                for (int i = 0; i < interactableList.Length; i++)
                {
                    var interactableData = interactableList[i];
                    var gameObject = interactableData.gameObject;
                    var name = gameObject.name;
                    if (int.TryParse(name, out var id))
                    {
                        interactableId = Mathf.Max(id, interactableId);
                        interactableData.id = interactableId;
                    }
                    else
                    {
                        interactableData.id = -1;
                    }
                    mapData.interactables.Add(interactableData);
                    //removeObjectList.Add(interactableData.gameObject.transform);
                }
            }
            //找到没有分配id的交互物
            for (int i = 0; i < mapData.interactables.Count; i++)
            {
                if (mapData.interactables[i].id == -1)
                {
                    interactableId++;
                    mapData.interactables[i].id = interactableId;
                    mapData.interactables[i].gameObject.name = interactableId.ToString();
                }
            }
            
            for (int i = 0; i < removeObjectList.Count; i++)
            {
                GameObject.DestroyImmediate(removeObjectList[i].gameObject);
            }

            mapData.obstacles = new List<MapObstacleData>();
            var obstacles = mapData.gameObject.GetComponentsInChildren<MapObstacleData>();
            for (int i = 0; i < obstacles.Length; i++)
            {
                if (obstacles[i].createEnvironmentUnit)
                {
                    mapData.obstacles.Add(obstacles[i]);
                }
            }
            
            mapData.spawnSafePoints.Clear();
            var spawnRoot = mapData.transform.Find("SpawnSafePoints");
            if (spawnRoot != null)
            {
                for (int i = 0; i < spawnRoot.childCount; i++)
                {
                    var child = spawnRoot.GetChild(i);
                    mapData.spawnPoints.Add(child.transform.position);
                }
            }
            
            var path = AssetDatabase.GetAssetPath(newObject);
            if (string.IsNullOrEmpty(path))
            {
                path = "Assets/ResourcesAssets/Pve/Survivor/Prefabs/MapData/"+this.mapData.gameObject.name+".prefab";
            }
            PrefabUtility.SaveAsPrefabAsset(newObject, path);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            GameObject.DestroyImmediate(newObject);
        }

        private void LoadPath()
        {
            if (mapData.truckPath.Count > 0)
            {
                var path = mapData.truckPath[0];
                var truck = mapData.GetComponentInChildren<TruckWheel>();
                if (truck != null)
                {
                    truck.ShowDebug(path);
                }
            }
        }

        private void CreatePath()
        {
            var truck = mapData.GetComponentInChildren<TruckWheel>();
            var routeRoot = mapData.transform.Find("RouteRoot");
            if (routeRoot != null)
            {
                for (int i = 0; i < routeRoot.childCount; i++)
                {
                    var child = routeRoot.GetChild(i);
                    var route = new MapRoute();
                    route.id = i + 1;
                    route.points = new List<Vector3>();
                    for (int j = 0; j < child.childCount; j++)
                    {
                        var point = child.GetChild(j);
                        route.points.Add(point.position);
                    }
                    mapData.routes.Add(route);
                    if (truck != null)
                    {
                        truck.SimulatePathCircle(route, 3);
                    }
                }
            }
        }

        
        private void SavePath()
        {
            var truck = mapData.GetComponentInChildren<TruckWheel>();
            if (truck != null)
            {
                var path = truck.SavePath();
                if (path != null)
                {
                    mapData.truckPath.Clear();
                    mapData.truckPath.Add(path);
                    BattleDebug.LogError("成功");
                }
            }
        }

        private List<string> filterList = new List<string>
        {
            "FeatureAirWall",
            "MonsterRoot",
            "PointRoot",
        };
        public void GenerateSpawnPoint()
        {
            //生成navmesh
            var centerPos = Vector3.zero;
            NavMeshPath path = new NavMeshPath();
            NavMeshBakeHelper.Clear();
            for (int i = 0; i < filterList.Count; i++)
            {
                var child = mapData.transform.Find(filterList[i]);
                if (child != null)
                {
                    child.gameObject.SetActive(false);
                }
            }
            var navmeshBakeHelper = mapData.gameObject.GetComponentInChildren<NavMeshBakeHelper>();
            if (navmeshBakeHelper)
            {
                NavMeshBakeHelper.BakeNavMesh();
                centerPos = navmeshBakeHelper.transform.position;
            }
            //var navMeshInstance = NavMesh.AddNavMeshData(mapData.navMeshData);
            var forward = Vector3.forward;
            var forwardObject = mapData.transform.Find("SpawnRegionForward");
            if (forwardObject != null)
            {
                forward = forwardObject.forward;
            }
            var gap = mapData.spawnPointGridSize;
            mapData.spawnPoints.Clear();
            var center = mapData.transform.Find("Center");
            var width = 200;
            var height = 200;
            var centerPosition = center.position;
            var helper = center.gameObject.GetComponent<NavMeshBakeHelper>();
            if (helper != null)
            {
                width = (int)helper.x;
                height = (int)helper.z;
            }
            var spawnRoot = mapData.transform.Find("SpawnRegion");
            if (spawnRoot != null)
            {
                var regionList = new List<List<Vector3>>();
                for (int i = 0; i < spawnRoot.childCount; i++)
                {
                    var region = spawnRoot.GetChild(i);
                    var points = new List<Vector3>();
                    for (int j = 0; j < region.childCount; j++)
                    {
                        var child = region.GetChild(j);
                        var position = child.position;
                        points.Add(position);
                    }
                    regionList.Add(points);
                }

                var xCount = width / gap;
                var yCount = height / gap;
                for (int i = 0; i < xCount; i++)
                {
                    for (int j = 0; j < yCount; j++)
                    {
                        var posX = -width / 2f + i * gap;
                        var posZ = -height / 2f + j * gap;
                        var point = new Vector3(posX, 0, posZ);
                        point = Quaternion.AngleAxis(PveUtils.GetAngle(Vector3.forward, forward), Vector3.up) * point +
                                new Vector3(centerPosition.x, 0, centerPosition.z);
                        for (int k = 0; k < regionList.Count; k++)
                        {
                            if (MapFogUtility.CheckPointIsInPolygon(regionList[k], point))
                            {
                                //判断是否navmesh有效
                                var hit = NavMesh.SamplePosition(point, out var hitPos, 0.5f, NavMesh.AllAreas);
                                var distance = Vector3.Distance(hitPos.position,
                                    new Vector3(point.x, hitPos.position.y, point.z));
                                if (hit && distance < 0.01f)
                                {
                                    if (NavMesh.CalculatePath(centerPos,point, NavMesh.AllAreas, path))
                                    {
                                        if (path.status == NavMeshPathStatus.PathComplete)
                                        {
                                            mapData.spawnPoints.Add(new Vector2(point.x,point.z));
                                            break;
                                        }
                                    }
                                }
                                else
                                {
                                    //BattleDebug.LogError(point + " 无效");
                                }
                            }
                        }
                    }
                }
            }
            //测试
            var obj = new GameObject();
            for (int i = 0; i < mapData.spawnPoints.Count; i++)
            {
                var point = mapData.spawnPoints[i];
                var child = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                child.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f);
                child.transform.position = new Vector3(point.x,0,point.y);
                child.transform.parent = obj.transform;
            }
            //NavMesh.RemoveNavMeshData(navMeshInstance);
            for (int i = 0; i < filterList.Count; i++)
            {
                var child = mapData.transform.Find(filterList[i]);
                if (child != null)
                {
                    child.gameObject.SetActive(true);
                }
            }
        }

        private void AddHpState()
        {
            var mapObstacle = mapData.gameObject.GetComponentsInChildren<MapObstacleData>();
            for (int i = 0; i < mapObstacle.Length; i++)
            {
                var hp = mapObstacle[i].GetComponent<HpStateDisplay>();
                if (hp == null)
                {
                    hp = mapObstacle[i].gameObject.AddComponent<HpStateDisplay>();
                    hp.CopyFromObstacle(mapObstacle[i]);
                }
            }
        }
    }
}
